package com.zyao89.view.zloading.path;

import com.zyao89.view.zloading.base.BaseStateBuilder;
import com.zyao89.view.zloading.util.NumCalcUtil;
import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorValue;
import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.render.Path;
import ohos.agp.render.PathMeasure;
import ohos.agp.utils.Point;
import ohos.agp.utils.RectFloat;
import ohos.app.Context;

import java.util.LinkedList;

/**
 * Created by zyao89 on 2018/3/11.
 * Contact me at 305161066@qq.com or zyao89@gmail.com
 * For more projects: https://github.com/zyao89
 * My Blog: https://zyao89.cn
 */
public class MusicPathBuilder extends BaseStateBuilder {

    private static final int MUSIC_LINE_COUNT = 5;
    private Paint mPaint;
    private float mR;

    private LinkedList<Path> mMusicPaths;
    private LinkedList<Path> mMusicDrawPaths;
    private PathMeasure mPathMeasure;
    private LinkedList<MusicParam> mMusicParams;
    private boolean mOpenJump = false;

    @Override
    protected int getStateCount() {
        return 3;
    }

    @Override
    protected void initParams(Context context, Paint paint) {
        System.out.println("initPaths====" + paint.getColor());
        mPaint = paint;
        mPaint.setStrokeWidth(2);
        mR = getAllSize();
        initPaths();
        initPathMeasure();
        initMusicParams();
    }

    private void initPaths() {
        mMusicPaths = new LinkedList<Path>();
        // 线长
        float lineW = mR * 2;

        // 线间距
        float space = mR * 2 / MUSIC_LINE_COUNT;

        // 起点
        float startXP = NumCalcUtil.subtract(getViewCenterX(), mR);
        float startYP = NumCalcUtil.add(getViewCenterY(), mR);

        // 五线谱
        for (int i = 0; i < MUSIC_LINE_COUNT; i++) {
            Path path = new Path();
            path.moveTo(startXP, NumCalcUtil.subtract(startYP, i * space));
            path.lineTo(NumCalcUtil.add(startXP, lineW), NumCalcUtil.subtract(startYP, i * space));
            mMusicPaths.add(path);
        }
    }

    private void initPathMeasure() {
        mMusicDrawPaths = new LinkedList<>();
        // 五线谱
        for (int i = 0; i < MUSIC_LINE_COUNT; i++) {
            Path drawPath = new Path();
            mMusicDrawPaths.add(drawPath);
        }
        Path mDrawPath = new Path();
        mPathMeasure = new PathMeasure(mDrawPath, false);
    }

    private void initMusicParams() {
        float musicWidth = mR * 0.2f;
        float musicHeight = mR;
        mMusicParams = new LinkedList<>();

        float musicPointHeight = mR * 2 / MUSIC_LINE_COUNT;
        float left = NumCalcUtil.subtract(getViewCenterX(), musicWidth / 2);
        float right = NumCalcUtil.add(getViewCenterX(), musicWidth / 2);
        float top = NumCalcUtil.subtract(NumCalcUtil.add(getViewCenterY(), musicHeight), musicPointHeight * 1.5f);
        float bottom = NumCalcUtil.subtract(NumCalcUtil.add(getViewCenterY(), musicHeight), musicPointHeight * 0.5f);

        RectFloat rectF = new RectFloat(NumCalcUtil.subtract(left, mR * 0.5f), top, NumCalcUtil.subtract(right, mR * 0.5f), bottom);
        float offsetX = (float) (musicWidth * 0.5 * Math.cos(75));
        Point sPointF = new Point(NumCalcUtil.add(rectF.right, offsetX), rectF.getVerticalCenter());
        Point ePointF = new Point(NumCalcUtil.add(rectF.right, offsetX), NumCalcUtil.subtract(rectF.getVerticalCenter(), musicHeight));
        MusicParam musicParam = new MusicParam(rectF, sPointF, ePointF);
        mMusicParams.add(musicParam);

        rectF = new RectFloat(NumCalcUtil.add(left, mR * 0.5f), NumCalcUtil.subtract(top, musicPointHeight), NumCalcUtil.add(right, mR * 0.5f), NumCalcUtil.subtract(bottom, musicPointHeight));
        offsetX = (float) (musicWidth * 0.5 * Math.cos(75));
        sPointF = new Point(NumCalcUtil.add(rectF.right, offsetX), rectF.getVerticalCenter());
        ePointF = new Point(NumCalcUtil.add(rectF.right, offsetX), NumCalcUtil.subtract(rectF.getVerticalCenter(), musicHeight));
        musicParam = new MusicParam(rectF, sPointF, ePointF);
        mMusicParams.add(musicParam);
    }

    @Override
    protected void onComputeUpdateValue(AnimatorValue animation, float animatedValue, int state) {

        switch (state) {
            case 0:
                animation.setCurveType(Animator.CurveType.DECELERATE);
                resetDrawPath();
                for (int i = 0; i < MUSIC_LINE_COUNT; i++) {
                    mPathMeasure.setPath(mMusicPaths.get(i), false);
                    if (i % 2 == 0) {
                        float stop = mPathMeasure.getLength() * animatedValue;
                        float start = (float) (stop - ((0.5 - Math.abs(animatedValue - 0.5)) * 200f));
                        mPathMeasure.getSegment(start, stop, mMusicDrawPaths.get(i), true);
                    } else {
                        double stop = mPathMeasure.getLength() * NumCalcUtil.subtract(1, animatedValue);
                        float start = (float) (stop - ((0.5 - Math.abs((1 - (double)animatedValue) - 0.5)) * 200f));
                        mPathMeasure.getSegment(start, (float) stop, mMusicDrawPaths.get(i), true);
                    }
                }
                break;
            case 1:
                resetDrawPath();
                for (int i = 0; i < MUSIC_LINE_COUNT; i++) {
                    mPathMeasure.setPath(mMusicPaths.get(i), false);
                    if (i % 2 == 0) {
                        float stop = mPathMeasure.getLength() * animatedValue;
                        float start = 0;
                        mPathMeasure.getSegment(start, stop, mMusicDrawPaths.get(i), true);
                    } else {
                        float stop = mPathMeasure.getLength();
                        float start = mPathMeasure.getLength() * NumCalcUtil.subtract(1, animatedValue);
                        mPathMeasure.getSegment(start, stop, mMusicDrawPaths.get(i), true);
                    }
                }
                break;
            case 2:
                animation.setCurveType(Animator.CurveType.BOUNCE);
                // jump
                mOpenJump = true;
                // 线间距
                float space = mR * 2 / MUSIC_LINE_COUNT;
                for (int i = 0; i < mMusicParams.size(); i++) {
                    MusicParam musicParam = mMusicParams.get(i);
                    if (i % 2 == 0) {
                        musicParam.setOffsetY(animatedValue * space);
                    } else {
                        musicParam.setOffsetY(NumCalcUtil.subtract(1, animatedValue) * space);
                    }
                }
                break;
            case 3:
                // jump
                mOpenJump = true;
                // 线间距
                space = mR * 2 / MUSIC_LINE_COUNT;
                for (int i = 0; i < mMusicParams.size(); i++) {
                    MusicParam musicParam = mMusicParams.get(i);
                    if (i % 2 == 0) {
                        musicParam.setOffsetY(NumCalcUtil.subtract(1, animatedValue) * space);
                    } else {
                        musicParam.setOffsetY(animatedValue * space);
                    }
                }
                break;
            default:
                break;
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        for (Path drawPath : mMusicDrawPaths) {
            canvas.drawPath(drawPath, mPaint);
        }
        if (mOpenJump) {
            drawMusic(canvas);
        }
    }

    private void drawMusic(Canvas canvas) {
        for (MusicParam musicParam : mMusicParams) {
            mPaint.setStrokeWidth(4);
            canvas.save();
            RectFloat oldCircleRectF = musicParam.getCircleRectF();
            RectFloat circleRectF = new RectFloat(oldCircleRectF);
            float offsetY = musicParam.getOffsetY();
            circleRectF.fuse(oldCircleRectF.left, NumCalcUtil.subtract(oldCircleRectF.top, offsetY), oldCircleRectF.right, NumCalcUtil.subtract(oldCircleRectF.bottom, offsetY));
            canvas.rotate(75, circleRectF.getHorizontalCenter(), circleRectF.getVerticalCenter());
            mPaint.setStyle(Paint.Style.FILLANDSTROKE_STYLE);
            canvas.drawOval(circleRectF, mPaint);
            mPaint.setStyle(Paint.Style.STROKE_STYLE);
            canvas.restore();

            Point startPointF = musicParam.getLineStartPointF();
            Point endPointF = musicParam.getLineEndPointF();
            canvas.drawLine(startPointF, endPointF, mPaint);
            mPaint.setStrokeWidth(2);
        }
    }

    @Override
    protected void prepareStart(AnimatorValue animation) {
        animation.setCurveType(Animator.CurveType.DECELERATE);
    }

    @Override
    protected void prepareEnd() {

    }

    private void resetDrawPath() {
        mOpenJump = false;
        for (Path path : mMusicDrawPaths) {
            path.reset();
            path.lineTo(0, 0);
        }
        for (MusicParam musicParam : mMusicParams) {
            musicParam.clear();
        }
    }

    static class MusicParam {
        private final RectFloat mCircleRectF;
        private final Point mLineStartPointF;
        private final Point mLineEndPointF;
        private float mOffsetY = 0;

        MusicParam(RectFloat rectF, Point sPointF, Point ePointF) {
            mCircleRectF = rectF;
            mLineStartPointF = sPointF;
            mLineEndPointF = ePointF;
        }

        RectFloat getCircleRectF() {
            return mCircleRectF;
        }

        Point getLineStartPointF() {
            return mLineStartPointF;
        }

        Point getLineEndPointF() {
            return mLineEndPointF;
        }

        float getOffsetY() {
            return mOffsetY;
        }

        void setOffsetY(float v) {
            mOffsetY = v;
        }

        void clear() {
            mOffsetY = 0;
        }
    }
}
